package com.example.xunai.service.user.impl;

import com.example.xunai.dto.response.system.TokenUsageResponse;
import com.example.xunai.dto.response.user.TokenStatsResponse;
import com.example.xunai.entity.TokenUsage;
import com.example.xunai.repository.TokenUsageRepository;
import com.example.xunai.service.cache.CacheService;
import com.example.xunai.service.user.TokenUsageService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class TokenUsageServiceImpl implements TokenUsageService {

    private final TokenUsageRepository tokenUsageRepository;
    private final CacheService cacheService;

    @Override
    public void recordTokenUsage(Long userId, Long conversationId, Long messageId, String model,
                                 Integer inputTokens, Integer outputTokens) {
        try {
            TokenUsage usage = new TokenUsage();
            usage.setUserId(userId);
            usage.setConversationId(conversationId);
            usage.setMessageId(messageId);
            usage.setModel(model);
            usage.setInputTokens(inputTokens);
            usage.setOutputTokens(outputTokens);
            usage.setUsageDate(LocalDateTime.now());

            tokenUsageRepository.save(usage);
            log.debug("已记录token使用: 用户{}, 模型{}, 输入{}, 输出{}, 消息ID{}",
                    userId, model, inputTokens, outputTokens, messageId);

            // 清除相关的统计缓存，因为数据已更新
            clearTokenStatsCache(userId);
        } catch (Exception e) {
            log.error("记录token使用失败", e);
        }
    }

    @Override
    public void recordTokenUsage(Long userId, Long conversationId, String model,
                                 Integer inputTokens, Integer outputTokens) {
        recordTokenUsage(userId, conversationId, null, model, inputTokens, outputTokens);
    }

    @Override
    public TokenUsageResponse getUserTokenUsage(Long userId, LocalDate startDate, LocalDate endDate) {
        log.info("获取用户Token使用统计，用户ID: {}, 时间范围: {} 至 {}", userId, startDate, endDate);

        List<Map<String, Object>> modelStats = getUserTokenStats(userId, startDate, endDate);

        int totalInputTokens = 0;
        int totalOutputTokens = 0;

        List<TokenUsageResponse.ModelUsage> modelUsages = new ArrayList<>();
        for (Map<String, Object> stat : modelStats) {
            int inputTokens = ((Number) stat.getOrDefault("totalInputTokens", 0)).intValue();
            int outputTokens = ((Number) stat.getOrDefault("totalOutputTokens", 0)).intValue();
            int totalTokens = ((Number) stat.getOrDefault("totalTokens", 0)).intValue();

            totalInputTokens += inputTokens;
            totalOutputTokens += outputTokens;

            TokenUsageResponse.ModelUsage usage = TokenUsageResponse.ModelUsage.builder()
                    .model((String) stat.get("model"))
                    .inputTokens(inputTokens)
                    .outputTokens(outputTokens)
                    .totalTokens(totalTokens)
                    .build();
            modelUsages.add(usage);
        }

        return TokenUsageResponse.of(
                userId, startDate, endDate,
                totalInputTokens, totalOutputTokens, modelUsages
        );
    }

    @Override
    public TokenStatsResponse getUserTokenStatsSummary(Long userId, int days) {
        log.info("获取用户Token统计摘要，用户ID: {}, 天数: {}", userId, days);

        LocalDate endDate = LocalDate.now();
        LocalDate startDate = endDate.minusDays(days - 1);

        // 获取基础统计
        Map<String, Object> summary = getUserTokenSummary(userId, startDate, endDate);
        List<Map<String, Object>> dailyTrend = getUserDailyTokenTrend(userId, days);
        List<Map<String, Object>> modelDistribution = getUserTokenStats(userId, startDate, endDate);

        return TokenStatsResponse.of(
                userId,
                (Integer) summary.get("totalInputTokens"),
                (Integer) summary.get("totalOutputTokens"),
                (Integer) summary.get("modelCount"),
                dailyTrend,
                modelDistribution
        );
    }

    @Override
    public List<Map<String, Object>> getUserTokenStats(Long userId, LocalDate startDate, LocalDate endDate) {
        String dateRange = formatDateRange(startDate, endDate);
        String cacheKey = userId + ":" + dateRange;

        // 尝试从缓存获取
        Map<String, Object> cachedStats = cacheService.getCachedUserTokenStats(userId, dateRange);
        if (cachedStats != null && cachedStats.containsKey("statsList")) {
            log.debug("从缓存获取用户Token统计: {} - {}", userId, dateRange);
            @SuppressWarnings("unchecked")
            List<Map<String, Object>> statsList = (List<Map<String, Object>>) cachedStats.get("statsList");
            return statsList;
        }

        // 从数据库获取
        List<Map<String, Object>> statsList = tokenUsageRepository.getUserTokenStatsByModel(userId, startDate, endDate);

        // 缓存结果
        Map<String, Object> statsToCache = new HashMap<>();
        statsToCache.put("statsList", statsList);
        statsToCache.put("timestamp", System.currentTimeMillis());
        cacheService.cacheUserTokenStats(userId, dateRange, statsToCache);

        return statsList;
    }

    @Override
    public Map<String, Object> getUserTokenSummary(Long userId, LocalDate startDate, LocalDate endDate) {
        String dateRange = formatDateRange(startDate, endDate);

        // 尝试从缓存获取
        Map<String, Object> cachedSummary = cacheService.getCachedUserTokenStats(userId, dateRange);
        if (cachedSummary != null && cachedSummary.containsKey("summary")) {
            log.debug("从缓存获取用户Token汇总: {} - {}", userId, dateRange);
            @SuppressWarnings("unchecked")
            Map<String, Object> summary = (Map<String, Object>) cachedSummary.get("summary");
            return summary;
        }

        List<Map<String, Object>> statsList = getUserTokenStats(userId, startDate, endDate);

        Map<String, Object> summary = new HashMap<>();
        int totalInputTokens = 0;
        int totalOutputTokens = 0;
        int totalTokens = 0;
        int modelCount = 0;

        for (Map<String, Object> stat : statsList) {
            totalInputTokens += ((Number) stat.getOrDefault("totalInputTokens", 0)).intValue();
            totalOutputTokens += ((Number) stat.getOrDefault("totalOutputTokens", 0)).intValue();
            totalTokens += ((Number) stat.getOrDefault("totalTokens", 0)).intValue();
            modelCount++;
        }

        summary.put("totalInputTokens", totalInputTokens);
        summary.put("totalOutputTokens", totalOutputTokens);
        summary.put("totalTokens", totalTokens);
        summary.put("modelCount", modelCount);
        summary.put("statsDetails", statsList);
        summary.put("userId", userId);
        summary.put("startDate", startDate);
        summary.put("endDate", endDate);

        // 缓存汇总结果
        Map<String, Object> cacheData = new HashMap<>();
        cacheData.put("summary", summary);
        cacheData.put("timestamp", System.currentTimeMillis());
        cacheService.cacheUserTokenStats(userId, dateRange, cacheData);

        return summary;
    }

    @Override
    public List<Map<String, Object>> getUserDailyTokenTrend(Long userId, int days) {
        // 尝试从缓存获取
        List<Map<String, Object>> cachedTrend = cacheService.getCachedTokenTrend(userId, days);
        if (cachedTrend != null) {
            log.debug("从缓存获取Token趋势: {} - {}天", userId, days);
            return cachedTrend;
        }

        LocalDate endDate = LocalDate.now();
        LocalDate startDate = endDate.minusDays(days - 1);
        List<Map<String, Object>> trend = tokenUsageRepository.getUserDailyTokenTrend(userId, startDate, endDate);

        // 缓存趋势数据
        cacheService.cacheTokenTrend(userId, days, trend);

        return trend;
    }

    @Override
    public List<Map<String, Object>> getModelUsageStats(LocalDate startDate, LocalDate endDate) {
        return tokenUsageRepository.getModelUsageStats(startDate, endDate);
    }

    @Override
    public Map<String, Object> getSystemTokenSummary(LocalDate startDate, LocalDate endDate) {
        List<Map<String, Object>> modelStats = tokenUsageRepository.getModelUsageStats(startDate, endDate);

        Map<String, Object> summary = new HashMap<>();
        int totalInputTokens = 0;
        int totalOutputTokens = 0;
        int totalTokens = 0;

        Long totalUsers = tokenUsageRepository.countDistinctUsersByDateRange(startDate, endDate);
        Long totalConversations = tokenUsageRepository.countDistinctConversationsByDateRange(startDate, endDate);

        for (Map<String, Object> stat : modelStats) {
            totalInputTokens += ((Number) stat.getOrDefault("totalInputTokens", 0)).intValue();
            totalOutputTokens += ((Number) stat.getOrDefault("totalOutputTokens", 0)).intValue();
            totalTokens += ((Number) stat.getOrDefault("totalTokens", 0)).intValue();
        }

        summary.put("totalInputTokens", totalInputTokens);
        summary.put("totalOutputTokens", totalOutputTokens);
        summary.put("totalTokens", totalTokens);
        summary.put("totalUsers", totalUsers != null ? totalUsers : 0);
        summary.put("totalConversations", totalConversations != null ? totalConversations : 0);
        summary.put("modelStats", modelStats);
        summary.put("startDate", startDate);
        summary.put("endDate", endDate);

        return summary;
    }

    @Override
    public List<String> getUserRecentModels(Long userId, int limit) {
        List<String> models = tokenUsageRepository.findRecentModelsByUserId(userId);
        if (models.size() > limit) {
            return models.subList(0, limit);
        }
        return models;
    }

    @Override
    public List<TokenUsage> getConversationTokenUsage(Long conversationId) {
        return tokenUsageRepository.findByConversationIdOrderByUsageDateDesc(conversationId);
    }

    @Override
    public Map<String, Integer> getUserTotalTokenUsage(Long userId, LocalDate startDate, LocalDate endDate) {
        List<Map<String, Object>> stats = tokenUsageRepository.getUserTokenStatsByModel(userId, startDate, endDate);

        Map<String, Integer> result = new HashMap<>();
        int totalInput = 0;
        int totalOutput = 0;
        int total = 0;

        for (Map<String, Object> stat : stats) {
            totalInput += ((Number) stat.getOrDefault("totalInputTokens", 0)).intValue();
            totalOutput += ((Number) stat.getOrDefault("totalOutputTokens", 0)).intValue();
            total += ((Number) stat.getOrDefault("totalTokens", 0)).intValue();
        }

        result.put("totalInputTokens", totalInput);
        result.put("totalOutputTokens", totalOutput);
        result.put("totalTokens", total);

        return result;
    }

    @Override
    public List<TokenUsage> getUserTokenUsageRecords(Long userId, LocalDate startDate, LocalDate endDate) {
        return tokenUsageRepository.findByUserIdAndUsageDateBetween(userId, startDate, endDate);
    }

    @Override
    public boolean isUserExceededTokenLimit(Long userId, LocalDate startDate, LocalDate endDate, int limit) {
        Map<String, Integer> totalUsage = getUserTotalTokenUsage(userId, startDate, endDate);
        return totalUsage.getOrDefault("totalTokens", 0) > limit;
    }

    /**
     * 清除Token统计缓存
     */
    private void clearTokenStatsCache(Long userId) {
        // 这里可以清除特定用户的缓存
        log.debug("清除用户Token统计缓存: {}", userId);
    }

    /**
     * 格式化日期范围作为缓存键
     */
    private String formatDateRange(LocalDate startDate, LocalDate endDate) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        return startDate.format(formatter) + "_" + endDate.format(formatter);
    }
}